import axios from "axios";
import * as md from "./md";


class EventBus {
  private readonly hs: gt.other.EventBusHandle[] = [{
    type: /msgRecv/,
    callBack(data) {
      md.format.msg(data).then(d => {
        md.gd.msg.push(d);
      });
    },
  }];
  constructor () { }
  create(type: string | RegExp, callBack: (data: any) => any) {
    if (type && callBack instanceof Function) {
      this.hs.push({ type: new RegExp(type), callBack });
    }
  }
  arrival(type: string, data?: any) {
    for (const e of this.hs) {
      if (e.type.test(type)) {
        try { e.callBack(data); } catch (_) { this.remove(e.callBack); }
      }
    }
  }
  remove(callback: cbk) {
    let i = this.hs.length;
    while (i--) {
      if (this.hs[i].callBack == callback) {
        this.hs.splice(i, 1);
      }
    }
  }
}
const me = md.format.def.user as gt.sql.user;
async function logined(p: obj) {
  if (p && p.id) {
    api.mid = p.id;
    api.token = p.token;
    api.me = await format.user(p);
  }
}
export const
  geb = new EventBus(), createEvent = geb.create.bind(geb), arrivalEvent = geb.arrival.bind(geb), removeEvent = geb.remove.bind(geb),
  req = axios.create({
    baseURL: md.apiUrl,
    timeout: 10000,
    headers: { 'Content-Type': 'application/json;charset=utf-8' },
    method: "post",
  }),
  api = {
    me, mid: "", nav: [] as gt.components.TreeElMenuData[], gk: [] as string[],
    s: {
      /** 分销 */
      distribution: false,
      /** 代金券 */
      voucher: true
    },
    async login(data: { username: string, password: string; timeout?: number; }) {
      const res = await request(data, "/login");
      if (res) {
        await logined(res.data);
      }
      return this.me;
    },
    reg(data: { username: string; password: string; name: string; }) {
      return new Promise<string>(async (resolve) => {
        const res = await request(data, "/reg");
        if (typeof res.data.data.token === "string") {
          localStorage.setItem("token", res.data.data.token);
        }
        resolve(res.data.data);
      });
    },
    get token() {
      return sessionStorage.getItem("token") || localStorage.getItem("token") || "";
    },
    set token(p: string) { localStorage.setItem("token", p); },
    upload(name: string, file: File | string, other: obj, type: string) {
      return new Promise<string>((resolve, reject) => {
        if (typeof file == "string") {
          if (file.split(',').length === 2) {
            file = md.base64ToFile(file, name);
          } else {
            resolve(file);
            return;
          }
        }
        const formData = new FormData();
        formData.append("file", file, file.name);
        formData.append("name", name);
        formData.append("type", type);
        formData.append("other", other ? JSON.stringify(other) : "{}");
        axios.post("/upload", formData, { headers: { "Content-Type": "multipart/form-data", token: this.token } }).then(res => {
          if (res.data.url) {
            resolve(md.formatUrl(res.data.url, apiUrl));
          } else {
            msg("上传失败-" + res.data.message, "error");
            reject(res);
          }
        }).catch(err => {
          msg("发生其他错误", "error");
          reject(err);
        });
      });
    },
    async request(data?: any, type?: string) {
      if (!this.mid && api.token) {
        try {
          await logined(await request({}, "/user/me"));
        } catch (_) {
          return;
        }
      }
      if (!type) {
        try {
          type = "";
          throw new Error();
        } catch (e: any) {
          type = e.stack.split("\n")[2].replace(/\(.*\)/g, "").replace(/\sat\s/g, "").replace(/\s+/g, "") as string;
          type = type.substring(type.lastIndexOf(".") + 1);
        }
      }
      if (md.type(data) == "object" && typeof data.id != "undefined") {
        if (type.indexOf("Read") > 0 && (!data.id || !data.id.length)) {
          if (data["#page"]) {
            return Object.assign({ current: 1, size: 10, total: 0 }, data["#page"], { data: [] });
          }
          return [];
        }
      }
      if (!this.gk.length) {
        this.gk = Object.keys(gd);
        this.gk.sort().sort((a, b) => a.length - b.length);
      }
      return await request(data, md.formatUrl(type, md.apiUrl));
    },
    logout() {
      sessionStorage.clear();
      localStorage.clear();
    }
  };
function request(data: any, url: string) {
  return new Promise<any>(async (resolve, reject) => {
    await md.next();
    const d = { data, url }, md5 = md.md5(JSON.stringify(d));
    if (md.addCache(md5, resolve, reject)) {
      req(d).then(res => {
        md.execCache(md5, res.data);
      }).catch(() => {
        md.execCache(md5, undefined, 1);
      });
    }
  });
}

req.interceptors.request.use(config => {
  const token = sessionStorage.getItem("token") || localStorage.getItem("token");
  if (token) {
    config.headers.token = token;
  }
  return config;
}, err => {
  return Promise.reject(err);
});
req.interceptors.response.use(res => {
  if (typeof res.data.message == "string") {
    msg(res.data.message, res.data.type);
  }
  return res;
}, () => {
  msg("网络错误");
});
function init() {
  // @ts-ignore
  try { if (process.env.NODE_ENV === "development" && globalThis?.api) { location.reload(); } } catch (_) { }
  const exg = { createEvent, arrivalEvent, removeEvent, request, api, geb, md };
  for (const key in exg) {
    // @ts-ignore
    globalThis[key] = exg[key];
  }

}
init();